using SqlSugar;
using System.Reflection;
using SharedKernel.Infrastructure.Comm;
using OrderService.Domain.Repositories;
using OrderService.Infrastructure.Repositories;

namespace OrderService.Infrastructure
{
    /// <summary>
    /// 依赖注入扩展
    /// </summary>
    public static class DependencyInjection
    {
        private static IUserContext _userContext;
        private static IServiceProvider _serviceProvider;

        /// <summary>
        /// 注册基础设施服务
        /// </summary>
        /// <param name="services">服务集合</param> 
        /// <returns>服务集合</returns>
        public static IServiceCollection AddInfrastructure(this IServiceCollection services, ConfigurationManager configuration)
        {
            var slaveConnectionConfigs = new List<SlaveConnectionConfig>() {
                   new SlaveConnectionConfig() { 
                       //80%的概率请求数据库
                       HitRate=80,
                       ConnectionString=configuration["ConnectionStrings:ProductReadDB1"]
                   } ,
                   new SlaveConnectionConfig() {
                       //20%的概率请求数据库
                       HitRate=20,
                       ConnectionString=configuration["ConnectionStrings:ProductReadDB2"]
                   }
            };

            var masterConnectionConfigs = new List<ConnectionConfig>() {
               GetConnectionConfig(configuration,"ProductWriteDB1",slaveConnectionConfigs),
               GetConnectionConfig(configuration,"ProductWriteDB2",slaveConnectionConfigs)
            };

            // 注册SqlSugar
            services.AddScoped<ISqlSugarClient>(s =>
            {
                var database = new SqlSugarClient(masterConnectionConfigs, db =>
                {
                    ////也可以这里面循环
                    //db.GetConnection("ProductWriteDB1").Aop.OnLogExecuting = (sql, pars) =>
                    //{
                    //    Console.WriteLine("执行ProductWriteDB1库"+sql);
                    //};
                    //db.GetConnection("ProductWriteDB2").Aop.OnLogExecuting = (sql, pars) =>
                    //{
                    //    Console.WriteLine("执行ProductWriteDB2库"+sql);
                    //};
                    ////启用SQL日志
                    //db.Aop.OnLogExecuting = (sql, pars) =>
                    //{
                    //    Console.WriteLine(sql);
                    //    Console.WriteLine(string.Join(", ", pars.Select(p => $"{p.ParameterName}: {p.Value}")));
                    //}; 
                });
                return database;
            });

            // 注册仓储
            services.AddScoped<IOrderRepository, OrderRepository>();

            return services;
        }

        /// <summary>
        /// 使用基础设施服务
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseInfrastructure(this IApplicationBuilder builder)
        {
            _serviceProvider = builder.ApplicationServices;
            return builder;
        }

        /// <summary>
        /// 获取数据库连接配置
        /// </summary>
        /// <param name="configuration"></param>
        /// <param name="dbName"></param>
        /// <param name="slaveConnectionConfigs"></param>
        /// <returns></returns>
        private static ConnectionConfig GetConnectionConfig(ConfigurationManager configuration, string dbName, List<SlaveConnectionConfig> slaveConnectionConfigs)
        {
            return new ConnectionConfig()
            {
                ConnectionString = configuration[$"ConnectionStrings:{dbName}"],
                IsAutoCloseConnection = true,
                SlaveConnectionConfigs = slaveConnectionConfigs,
                DbType = DbType.MySql,
                ConfigId = dbName,
                InitKeyType = InitKeyType.Attribute,
                ConfigureExternalServices = new ConfigureExternalServices()
                {
                    //DataInfoCacheService = new SqlSugarRedisCache(nameof(RedisManager.AppClient)),

                    EntityNameService = (x, p) => //处理表名
                    {
                        p.DbTableName = UtilMethods.ToUnderLine(p.DbTableName);//驼峰转下划线方法
                        //排除特殊的D类
                        if (p.DbTableName.EndsWith("DTO") || p.DbTableName.EndsWith("ValueObject") || p.DbTableName.EndsWith("Request"))
                        {
                            p.DbTableName = p.DbTableName.Replace("DTO", "").Replace("ValueObject", "").Replace("Request", "");
                        }
                    },

                    //注意:  这儿AOP设置不能少
                    EntityService = (c, p) =>
                    {
                        /***低版C#写法***/
                        if (p.IsPrimarykey == false && c.PropertyType.IsGenericType && c.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                        {
                            p.IsNullable = true;
                        }

                        /***高版C#写法***/
                        if (p.IsPrimarykey == false && new NullabilityInfoContext().Create(c).WriteState is NullabilityState.Nullable)
                        {
                            p.IsNullable = true;
                        }
                    }
                },
                AopEvents = new AopEvents
                {
                    OnLogExecuting = (sql, pars) => //SQL执行前
                    {
                        ////获取原生SQL推荐 5.1.4.63  性能OK
                        //var sql1 = UtilMethods.GetNativeSql(sql, pars);

                        ////获取无参数化SQL 影响性能只适合调试
                        //var sql2 = UtilMethods.GetSqlString(DbType.SqlServer, sql, pars);
                    },
                    //实体操作之前，做AOP数据处理
                    DataExecuting = (oldValue, entityInfo) =>
                    {
                        //通过IHttpContextAccessor拿到当前用户信息 
                        var httpContextAccessor = _serviceProvider.GetService<IHttpContextAccessor>();
                        _userContext = httpContextAccessor?.HttpContext?.RequestServices.GetService<IUserContext>();

                        /*** 列级别事件：插入的每个列都会进事件 ***/
                        if (entityInfo.OperationType == DataFilterType.InsertByObject)
                        {
                            if (entityInfo.PropertyName == "CreateTime")
                            {
                                entityInfo.SetValue(DateTime.Now);
                            }
                            if (entityInfo.PropertyName == "CreateUserId")
                            {
                                if (_userContext != null)
                                {
                                    entityInfo.SetValue(_userContext.UserId.GetValueOrDefault());
                                }
                            }
                            if (entityInfo.PropertyName == "LastUpdateTime")
                            {
                                entityInfo.SetValue(DateTime.Now);
                            }
                            if (entityInfo.PropertyName == "LastUpdateUserId")
                            {
                                if (_userContext != null)
                                {
                                    entityInfo.SetValue(_userContext.UserId.GetValueOrDefault());
                                }
                            }
                        }
                        else if (entityInfo.OperationType == DataFilterType.UpdateByObject)
                        {
                            var isDeleted = false;
                            var properyIsDeleted = entityInfo.EntityValue.GetType().GetProperty("IsDeleted");
                            if (properyIsDeleted != null)
                            {
                                isDeleted = (bool)properyIsDeleted.GetValue(entityInfo.EntityValue);
                            }
                            //删除只更新删除的字段
                            if (isDeleted)
                            {
                                if (entityInfo.PropertyName == "DeletedTime")
                                {
                                    entityInfo.SetValue(DateTime.Now);
                                }
                                if (entityInfo.PropertyName == "DeletedUserId")
                                {
                                    if (_userContext != null)
                                    {
                                        entityInfo.SetValue(_userContext.UserId.GetValueOrDefault());
                                    }
                                }
                            }
                            //不是删除，只更新修改的字段
                            else
                            {
                                if (entityInfo.PropertyName == "LastUpdateTime")
                                {
                                    entityInfo.SetValue(DateTime.Now);
                                }
                                if (entityInfo.PropertyName == "LastUpdateUserId")
                                {
                                    if (_userContext != null)
                                    {
                                        entityInfo.SetValue(_userContext.UserId.GetValueOrDefault());
                                    }
                                }
                            }
                        }
                    },
                    //实体操作完成之后，拿到修改前、修改后的数据
                    OnDiffLogEvent = it =>
                    {
                        //操作前记录  包含： 字段描述 列名 值 表名 表描述
                        //插入Before为null，之前还没进库
                        var editBeforeData = it.BeforeData;
                        //操作后记录   包含： 字段描述 列名 值  表名 表描述
                        var editAfterData = it.AfterData;
                        var sql = it.Sql;
                        var parameter = it.Parameters;
                        var data = it.BusinessData;//这边会显示你传进来的对象
                        var time = it.Time;
                        var diffType = it.DiffType;//enum insert 、update and delete  


                    }
                },

            };

        }

    }
}